package cn.edu.scnu.semart.filter;

import cn.edu.scnu.semart.common.utils.JwtUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    // 白名单：登录、Swagger、knife4j
    private boolean isWhite(String path) {
        return path.startsWith("/auth") ||
                path.startsWith("/admin/user/save")||
                path.startsWith("/swagger") ||
                path.startsWith("/v2/api-docs") ||
                path.startsWith("/webjars") ||
                path.startsWith("/doc.html") ||
                path.startsWith("/cart")||
                path.startsWith("/category")||
                path.startsWith("/comment")||
                path.startsWith("/favorite")||
                path.startsWith("/audit")||
                path.startsWith("/goods")||
                path.startsWith("/ranking")||
                path.startsWith("api/images")||
                path.startsWith("/like")||
                path.startsWith("/chat/history")||
                path.startsWith("/chat.sendMessage")||
                path.startsWith("/chat")||
                path.startsWith("/orders")||
                path.startsWith("/stat/order")||
                path.startsWith("/payment")||
                path.startsWith("/admin/product");
//        暂时注释白名单，方便开发
//        return true;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 1. 白名单直接放行
        if (isWhite(path) || "OPTIONS".equalsIgnoreCase(request.getMethodValue())) {
            return chain.filter(exchange);
        }

        // 2. 取 token
        String auth = request.getHeaders().getFirst("Authorization");
        if (!StringUtils.hasText(auth) || !auth.startsWith("Bearer ")) {
            return unAuth(exchange);
        }

        String token = auth.substring(7);
        try {
            Integer userId  = JwtUtils.getUserId(token);
            String userType = JwtUtils.getUserType(token);

            // 3. 透传给下游
            ServerHttpRequest mutate = request.mutate()
                    .header("X-User-Id",   userId.toString())
                    .header("X-User-Type", userType)
                    .build();
            return chain.filter(exchange.mutate().request(mutate).build());

        }catch (io.jsonwebtoken.ExpiredJwtException e){
            return expired(exchange);
        }
        catch (Exception e) {
            return unAuth(exchange);
        }
    }

    private Mono<Void> expired(ServerWebExchange exchange) {
        ServerHttpResponse resp = exchange.getResponse();
        resp.setStatusCode(HttpStatus.FORBIDDEN); // 或继续 401
        resp.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String body = "{\"code\":403,\"message\":\"Token 已过期\"}";
        return resp.writeWith(Mono.just(resp.bufferFactory().wrap(body.getBytes())));
    }


    private Mono<Void> unAuth(ServerWebExchange exchange) {
        ServerHttpResponse resp = exchange.getResponse();
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        return resp.setComplete();
    }

    @Override
    public int getOrder() {
        return -100;   // 越小越先执行
    }
}
